import re

from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from apps.carts.utils import merge_cart_cookie_to_redis
from apps.users.models import User, Address
from django.http import JsonResponse, HttpResponseBadRequest
# 1.请求方式
# class UsernameCountView(View):
#     # 2. 请求参数：路径参数
#     def get(self, request, username):
#         # if not re.match('[a-zA-Z0-9_-]{5,20}',username):
#         #     return JsonResponse({'code':200,'errmsg':'用户名不满足需求'})
#         count=User.objects.filter(username=username).count()#数据库
#         # 3.响应结果：JSON
#         return JsonResponse({'code':0,'count':count,'errmsg':'ok'})
# class MoblieView(View):
#     def get(self, request, mobile):
#         count=User.objects.filter(mobile=mobile).count()
#         return JsonResponse({'code':0,'count':count,'errmsg':'ok'})
import json
from apps.verifications.views import SMSCodeView

#注册
class RegisterView(View):
    def post(self, request):
        #1
        body_bytes = request.body
        body_str = body_bytes.decode()
        body_dict = json.loads(body_str)
        #2
        username = body_dict.get('username')
        password = body_dict.get('password')
        password2 = body_dict.get('password2')
        mobile = body_dict.get('mobile')
        allow = body_dict.get('allow')

        #3
        if not all([username,password,password2,mobile,allow]):
            return JsonResponse({'code':400,'errmsg':'缺少必传参数!'})
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return JsonResponse({'code': 400, 'errmsg': 'username格式有误!'})
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': 400, 'errmsg': 'password格式有误!'})
        # 判断两次密码是否一致
        if password != password2:
            return JsonResponse({'code': 400, 'errmsg': '两次输入不对!'})
        # 判断手机号是否合法
        if not re.match(r'1[3-9]\d{9}', mobile):
            return JsonResponse({'code': 400, 'errmsg': 'mobile格式有误!'})
        # 判断是否勾选用户协议
        if allow != True:
            return JsonResponse({'code': 400, 'errmsg': 'allow格式有误!'})
        #4
        # User.objects.create(username=username, password=password, mobile=mobile)
        user=User.objects.create_user(username=username, password=password, mobile=mobile)#加密password
        sms_code = request.POST.get('sms_code')
        # 判断短信验证码是否正确：跟图形验证码的验证一样的逻辑
        # 提取服务端存储的短信验证码：以前怎么存储，现在就怎么提取
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)  # sms_code_server是bytes
        # 判断短信验证码是否过期
        if not sms_code_server:
            return JsonResponse({'code': 400, 'errmsg': '短信验证码失效'})
        # 对比用户输入的和服务端存储的短信验证码是否一致
        if sms_code!= sms_code_server.decode():
            return JsonResponse({'code': 400, 'errmsg': '短信验证码有误'})
        from django.contrib.auth import login
           # 实现状态保持
        login(request, user)
       # 响应注册结果
        return JsonResponse({'code': 0, 'errmsg': 'ok'})
 #登录
class LoginView(View):
    def post(self, request):
        #1.获得数据
        data = json.loads(request.body.decode())
        username = data.get('username')
        password = data.get('password')
        remember = data.get('remember')
        # remember = str(data.get('remember')).lower()
        #2.验证数据
        if not all([username,password]):
            return JsonResponse({'code':400,'errmsg':'参数不全'})
        #多账户登录
        import re
        if re.match('1[3-9]\d{9}', username):
            # 手机号
            User.USERNAME_FIELD = 'mobile'
        else:
            # account 是用户名
            # 根据用户名从数据库获取 user 对象返回.
            User.USERNAME_FIELD = 'username'
        #验证数据正确
        from django.contrib.auth import authenticate
        user = authenticate(username=username,password=password)
        if not user:
            return JsonResponse({'code':400,'errmsg':'账户或者密码错误'})
        from django.contrib.auth import login
        # 4.状态保持
        login(request, user)

        #5.是否记住(10天）--seetion有效期
        if remember :
            # 如果记住:  设置为两周有效,默认
            request.session.set_expiry(None)
        else:
            # 如果没有记住: 关闭立刻失效
            request.session.set_expiry(0)
        #6.   返回响应
        response = JsonResponse({'code': 0, 'errmsg': 'ok'})
        #Vue读取cookie渲染用户信息，首页用户名展示
        # 注册时用户名写入到cookie，有效期15天
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)
        # 合并购物车
        # 需求：用户登录时，将cookie购物车数据合并到Redis购物车数据中。
        from apps.carts.utils import merge_cart_cookie_to_redis
        response = merge_cart_cookie_to_redis(request=request, user=user, response=response)
        return response
from django.contrib.auth import logout
class LogoutView(View):
    """退出登录"""
    #delect和前端一至
    def delete(self, request):
        """实现退出登录逻辑"""
        # 清理session
        logout(request)
        # 退出登录，重定向到登录页
        response = JsonResponse({'code':0,'errmsg':'ok'})
        # 退出登录时清除cookie中的username
        response.delete_cookie('username')
        return response
"""用户中心"""
# from django.contrib.auth.mixins import LoginRequiredMixin
# class LoginRequiredJSONMixin(LoginRequiredMixin):
#     """Verify that the current user is authenticated."""
#     def handle_no_permission(self):
#         return JsonResponse({'code': 400, 'errmsg': '用户未登录'})
from utils.views import LoginRequiredJSONMixin
class UserInfoView(LoginRequiredJSONMixin, View):
    def get(self, request):
        """提供个人信息界面"""
        # 获取界面需要的数据,进行拼接
        info_data = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        # 返回响应
        return JsonResponse({'code': 0,'errmsg': 'ok','info_data': info_data})
class EmailView(LoginRequiredJSONMixin,View):
    """添加邮箱"""
    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')
        # 校验参数
        if not email:
            return JsonResponse({'code': 400,'errmsg': '缺少email参数'})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return JsonResponse({'code': 400,'errmsg': '参数email有误'})
        # 赋值email字段
        request.user.email = email
        request.user.save()
        from django.core.mail import send_mail
        subject='美多商城激活邮箱'#主题
        message=""
        from_email='美多商城<19103041310@163.com>'#发件人
        recipient_list = ['19103041310@163.com']#收件人
        #加密user_id,得到token
        from apps.users.utils import generate_access_token
        token = generate_access_token(request.user.id)
        # html_message="点击激活<a href='http:www.baidu.cn/?token=%s'>激活</a>"  # 内容
        token = generate_access_token(request.user.id)  # 生成 token
        verify_url = f'http://www.meiduo.site:8080/success_verify_email.html?token={token}'  # 添加 token
        html_message = f'''
            <p>尊敬的用户您好！</p>
            <p>感谢您使用美多商城。</p>
            <p>您的邮箱为：{email}。请点击此链接激活您的邮箱：</p>
            <p><a href="{verify_url}">{verify_url}</a></p>
        '''
        # send_mail(subject=subject,
        #           message=message,
        #           from_email=from_email,
        #           recipient_list=recipient_list,
        #           html_message=html_message
        #            )
        # 启动Celery服务:celery -A celery_tasks.main worker -l info
        from celery_tasks.email.tasks import celery_send_mail
        celery_send_mail.delay(
            subject=subject,
            message=message,
            from_email=from_email,
            recipient_list=recipient_list,
            html_message=html_message,
        )

        # 响应添加邮箱结果
        return JsonResponse({'code':0, 'errmsg': '添加邮箱成功'})
from apps.users.utils import check_access_token
class VerifyEmailView(View):
    def put(self, request):
        # - 1.接收 token
        token = request.GET.get('token')
        if not token:
            return JsonResponse({'code': 400, 'errmsg': 'token缺少'})
        # - 2.解密
        user_id = check_access_token(token)
        if not user_id:
            return JsonResponse({'code': 400, 'errmsg': 'user_id缺少'})
        # - 4.去数据库对比 user_id,email
        try:
            user = User.objects.get(id=user_id)
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '参数有误!'})
        # - 5.修改激活状态
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            return JsonResponse({'code': 0, 'errmsg': '激活失败!'})
#新增地址
class CreateAddressView(LoginRequiredJSONMixin, View):
    """新增地址"""
    def post(self, request, RETCODE=None):
        """实现新增地址逻辑"""
        # 判断是否超过地址上限：最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        if count >= 20:
            return JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})
        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return HttpResponseBadRequest('参数email有误')
        # 保存地址信息
        address = Address.objects.create(
                user=request.user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel,
                email = email
            )
            # 设置默认地址
        if not request.user.default_address:
                request.user.default_address = address
                request.user.save()

        # 新增地址成功，将新增的地址响应给前端实现局部刷新
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 响应保存结果
        return JsonResponse({'code': 0, 'errmsg': '新增地址成功', 'address':address_dict})
#展示地址
class AddressView(LoginRequiredJSONMixin,View):
    """用户收货地址"""
    def get(self, request):
        """提供地址管理界面
        """
        # 获取所有的地址:
        addresses = Address.objects.filter(user=request.user,
                                           is_deleted=False)
        # 创建空的列表
        address_dict_list = []
        # 遍历
        for address in addresses:
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }
            # 将默认地址移动到最前面
            default_address = request.user.default_address
            if default_address.id == address.id:
                # 查询集 addresses 没有 insert 方法
                address_dict_list.insert(0, address_dict)
            else:
                address_dict_list.append(address_dict)
        default_id = request.user.default_address_id
        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'addresses': address_dict_list,
                             'default_address_id': default_id})
#修改和删除地址
class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):
    """修改和删除地址"""
    def put(self, request, address_id):
        """修改地址"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400,
                                      'errmsg': '缺少必传参数'})
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                      'errmsg': '参数mobile有误'})
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return JsonResponse({'code': 400,
                                          'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return JsonResponse({'code': 400,
                                          'errmsg': '参数email有误'})
        # 判断地址是否存在,并更新地址信息
        Address.objects.filter(id=address_id).update(
                user = request.user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel,
                email = email
            )
        # 构造响应数据
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 响应更新地址结果
        return JsonResponse({'code': 0, 'errmsg': '更新地址成功', 'address': address_dict})
    def delete(self, request, address_id):
        """删除地址"""
        # 查询要删除的地址
        try:
            address = Address.objects.get(id=address_id)
            # 将地址逻辑删除设置为    True
            address.is_deleted = True
            address.save()
        except Exception as e:
            return JsonResponse({'code': 400, 'errmsg': '删除地址失败'})
        # 响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '删除地址成功'})

class DefaultAddressView(LoginRequiredJSONMixin, View):
    """设置默认地址"""
    def put(self, request, address_id):
        """设置默认地址"""
        # 接收参数,查询地址
        address = Address.objects.get(id=address_id)
        # 设置地址为默认地址
        request.user.default_address = address
        request.user.save()

        # 响应设置默认地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功'})
class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    """设置地址标题"""
    def put(self, request, address_id):
        """设置地址标题"""
        # 接收参数：地址标题
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')
        # 查询地址
        address = Address.objects.get(id=address_id)
        # 设置新的地址标题
        address.title = title
        address.save()
        # 4.响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置地址标题成功'})
class ChangePasswordView(LoginRequiredMixin, View):
    """修改密码"""
    def put(self, request):
        """实现修改密码逻辑"""
        # 接收参数
        dict = json.loads(request.body.decode())
        old_password = dict.get('old_password')
        new_password = dict.get('new_password')
        new_password2 = dict.get('new_password2')
        # 校验参数
        if not all([old_password, new_password, new_password2]):
           return JsonResponse({'code':400,
                                     'errmsg':'缺少必传参数'})
        result = request.user.check_password(old_password)
        if not result:
            return JsonResponse({'code':400,
                                      'errmsg':'原始密码不正确'})
        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code':400,
                                      'errmsg':'密码最少8位,最长20位'})
        if new_password != new_password2:
            return JsonResponse({'code':400,
                                      'errmsg':'两次输入密码不一致'})
        # 修改密码
        request.user.set_password(new_password)
        request.user.save()
        # 清理状态保持信息
        logout(request)
        response = JsonResponse({'code':0,
                                      'errmsg':'ok'})
        response.delete_cookie('username')
        # # 响应密码修改结果：重定向到登录界面
        return response
from apps.goods.models import SKU
from django_redis import get_redis_connection

class UserBrowseHistory(LoginRequiredJSONMixin, View):
    """用户浏览记录"""
    def post(self, request):
        """保存用户浏览记录"""
        user=request.user#登录才保存
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 校验参数
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': 'sku不存在'})

        # 保存用户浏览数据
        redis_conn = get_redis_connection('history')
        pl = redis_conn.pipeline()
        user_id = request.user.id

        # 先去重
        pl.lrem('history_%s' % user_id, 0, sku_id)
        # 再存储
        pl.lpush('history_%s' % user_id, sku_id)
        # 最后截取，5个
        pl.ltrim('history_%s' % user_id, 0, 4)
        # 执行管道
        pl.execute()

        # 响应结果
        return JsonResponse({'code': 0, 'errmsg': 'OK'})

    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return JsonResponse({'code': 0, 'errmsg': 'OK', 'skus': skus})



